package com.example.demo.service.impl;

import com.example.demo.exception.CustomException;
import com.example.demo.model.dto.LoginDTO;
import com.example.demo.model.dto.RegisterDTO;
import com.example.demo.model.entity.relation.TeacherStudentRelation;
import com.example.demo.mapper.TeacherStudentRelationMapper;
import com.example.demo.mapper.UserMapper;
import com.example.demo.model.entity.user.User;
import com.example.demo.model.enums.UserStatus;
import com.example.demo.model.enums.UserTypeEnum;
import com.example.demo.security.JwtTokenProvider;
import com.example.demo.service.AuthService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Objects;

@Slf4j
@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {

    private static final String DEFAULT_AVATAR = "default-avatar.jpg";
    private static final String DEFAULT_RELATION_TYPE = "DEFAULT";

    private final UserMapper userMapper;
    private final PasswordEncoder passwordEncoder;
    private final JwtTokenProvider jwtTokenProvider;
    private final TeacherStudentRelationMapper relationMapper;

    @Override
    @Transactional(readOnly = true)
    public User authenticateUser(LoginDTO loginDTO) {
        Objects.requireNonNull(loginDTO, "登录参数不能为空");
        if (StringUtils.isBlank(loginDTO.getUsername()) || StringUtils.isBlank(loginDTO.getPassword())) {
            throw new CustomException("用户名和密码不能为空", HttpStatus.BAD_REQUEST);
        }

        log.debug("尝试登录用户: {}", loginDTO.getUsername());


        User user = userMapper.findByUsername(loginDTO.getUsername())
                .orElseThrow(() -> {
                    log.warn("登录失败 - 用户不存在: {}", loginDTO.getUsername());
                    return new CustomException("用户名或密码错误", HttpStatus.UNAUTHORIZED);
                });

        validateUserForLogin(user, loginDTO.getPassword());
        log.info(user.toString());
        log.info("从数据库加载的用户数据: userId={}, username={}, userType={}",
                user.getUserId(), user.getUsername(), user.getUserType());
        log.info("用户登录成功: {} (类型: {})",
                loginDTO.getUsername(),
                user.getUserType().getDescription());
        return user;
    }

    @Override
    @Transactional
    public User registerUser(RegisterDTO registerDTO) {
        validateRegisterDTO(registerDTO);

        User user = buildUserFromRegisterDTO(registerDTO);
        user.setUserType(registerDTO.getRole() != null ?
                registerDTO.getRole() :
                UserTypeEnum.STUDENT);

        userMapper.insert(user);
        log.info("用户注册成功: {} (类型: {})",
                user.getUsername(),
                user.getUserType().getDescription());
        return user;
    }

    @Override
    @Transactional
    public String refreshAccessToken(String refreshToken) {
        if (!jwtTokenProvider.validateToken(refreshToken)) {
            log.warn("刷新令牌失败 - 令牌无效");
            throw new CustomException("无效的刷新令牌", HttpStatus.UNAUTHORIZED);
        }

        if (!jwtTokenProvider.isRefreshToken(refreshToken)) {
            log.warn("刷新令牌失败 - 令牌类型错误");
            throw new CustomException("请提供有效的刷新令牌", HttpStatus.BAD_REQUEST);
        }

        String username = jwtTokenProvider.getUsernameFromToken(refreshToken);
        User user = getUserWithValidation(username);

        log.info("刷新令牌成功: {}", username);
        return jwtTokenProvider.generateAccessToken(user);
    }

    @Override
    @Transactional(readOnly = true)
    public User getCurrentUser(String username) {
        Objects.requireNonNull(username, "用户名不能为空");
        return getUserWithValidation(username);
    }

    @Override
    @Transactional
    public User registerTeacher(RegisterDTO registerDTO) {
        validateRegisterDTO(registerDTO);

        User teacher = buildUserFromRegisterDTO(registerDTO);
        teacher.setUserType(UserTypeEnum.TEACHER);

        userMapper.insert(teacher);
        log.info("教师注册成功: {}", teacher.getUsername());
        return teacher;
    }

    @Override
    @Transactional
    public User registerStudent(RegisterDTO registerDTO, Long teacherId) {
        validateRegisterDTO(registerDTO);
        Objects.requireNonNull(teacherId, "教师ID不能为空");

        User student = buildUserFromRegisterDTO(registerDTO);
        student.setUserType(UserTypeEnum.STUDENT);
        userMapper.insert(student);

        createTeacherStudentRelation(teacherId, student.getUserId());
        log.info("学生注册成功: {} (指导教师ID: {})", student.getUsername(), teacherId);
        return student;
    }

    @Override
    public User getCurrentUserFromToken(String jwt) {
        String username = jwtTokenProvider.getUsernameFromToken(jwt);
        return getUserWithValidation(username);
    }

    // ============= 私有方法 =============
    private void validateUserForLogin(User user, String rawPassword) {
        if (!passwordEncoder.matches(rawPassword, user.getPassword())) {
            log.warn("登录失败 - 密码错误 (用户: {})", user.getUsername());
            throw new CustomException("用户名或密码错误", HttpStatus.UNAUTHORIZED);
        }

        if (user.getStatus() == UserStatus.DISABLED.getCode()) {
            log.warn("登录失败 - 账号已禁用 (用户: {})", user.getUsername());
            throw new CustomException("账号已被禁用，请联系管理员", HttpStatus.FORBIDDEN);
        }

        // 确保userType不为null
        if (user.getUserType() == null) {
            log.error("系统异常 - 用户类型为空 (用户ID: {})", user.getUserId());
            throw new CustomException("系统数据异常，请联系管理员", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    private User getUserWithValidation(String username) {
        User user = userMapper.findByUsername(username)
                .orElseThrow(() -> {
                    log.warn("用户不存在: {}", username);
                    return new CustomException("用户不存在", HttpStatus.NOT_FOUND);
                });

        if (user.getStatus() == UserStatus.DISABLED.getCode()) {
            log.warn("账号已禁用: {}", username);
            throw new CustomException("账号已被禁用", HttpStatus.FORBIDDEN);
        }

        // 防御性检查
        if (user.getUserType() == null) {
            log.error("用户类型数据异常: {}", username);
            user.setUserType(UserTypeEnum.STUDENT); // 自动修复
            userMapper.update(user);
        }

        return user;
    }

    private void validateRegisterDTO(RegisterDTO dto) {
        Objects.requireNonNull(dto, "注册参数不能为空");

        if (userMapper.existsByUsername(dto.getUsername())) {
            log.warn("注册失败 - 用户名已存在: {}", dto.getUsername());
            throw new CustomException("用户名已被使用", HttpStatus.BAD_REQUEST);
        }

        if (userMapper.existsByEmail(dto.getEmail())) {
            log.warn("注册失败 - 邮箱已注册: {}", dto.getEmail());
            throw new CustomException("该邮箱已被注册", HttpStatus.BAD_REQUEST);
        }

        if (StringUtils.isBlank(dto.getPassword()) || dto.getPassword().length() < 6) {
            log.warn("注册失败 - 密码强度不足");
            throw new CustomException("密码长度至少为6位", HttpStatus.BAD_REQUEST);
        }
    }

    private User buildUserFromRegisterDTO(RegisterDTO dto) {
        User user = new User();
        user.setUsername(dto.getUsername());
        user.setPassword(passwordEncoder.encode(dto.getPassword()));
        user.setName(dto.getRealName());
        user.setEmail(dto.getEmail());
        user.setPhone(Objects.toString(dto.getPhone(), ""));
        user.setAvatar(StringUtils.defaultIfBlank(dto.getAvatar(), DEFAULT_AVATAR));
        user.setStatus(UserStatus.ENABLED.getCode());
        return user;
    }

    private void createTeacherStudentRelation(Long teacherId, Long studentId) {
        TeacherStudentRelation relation = new TeacherStudentRelation();
        relation.setTeacherId(teacherId);
        relation.setStudentId(studentId);
        relation.setRelationType(DEFAULT_RELATION_TYPE);
        relation.setCreateTime(LocalDateTime.now());
        relationMapper.insert(relation);
    }
}